Bindings
A binding is used to configure
wire-level invocation details for a service. Service consumers are
required to communicate with a service by complying to the binding
requirements specified in the service endpoint. A binding is
represented by the binding class in WCF; the binding class contains a
name, namespace, and a collection of binding elements (Figure 3).
The name and namespace uniquely identify the binding within the overall service metadata. Figure 4 lists the various binding elements that can be used to further specific binding requirements.
Through
its extensibility features, WCF service binding supports binary
encoding for performance, MTOM for large payloads, and text and custom
encoding.
WCF provides a set of
pre-defined binding that can simplify the creation of service endpoints
if you find one that meets your requirements. These “system-provided”
bindings are listed in Table 1.
Table 1. A list of the system-provided WCF bindings.
Name | Purpose |
---|
BasicHttpBinding | interoperability with Web services supporting the WS-BasicProfile 1.1 and Basic Security Profile 1.0 |
WSHttpBinding | interoperability with Web services supporting the WS-* protocols over HTTP |
WSDualHttpBinding | duplex
HTTP communication where the receiver of an initial message will not
reply directly to the initial sender (but may transmit any number of
responses over a period of time via HTTP in conformity with WS-*
protocols) |
WSFederationBinding | HTTP
communication where access to the resources of a service can be
controlled based on the credentials issued by an explicitly-identified
credential provider |
NetTcpBinding | secure, reliable, high-performance communication between WCF services across a network |
NetNamedPipeBinding | secure, reliable, high-performance communication between WCF services on the same machine |
NetMsmqBinding | communication between WCF services via MSMQ |
MsmqIntegrationBinding | communication between a WCF service and another software program via MSMQ |
NetPeerTcpBinding | communication between WCF services via Windows Peer-to-Peer Networking |
NetTcpRelayBinding | enables
a service to work with service bus features from the .NET Services
offerings in the Windows Azure Services platform (the service bus is a
relay service that makes it possible to establish connectivity through
clouds across organizational boundaries) |
BasicHttpRelayBinding | the BasicHttpBinding
maps to this binding to enable a service to work with service bus
features from .NET Services (the relay counterpart establishes a
listener in the cloud instead of listening locally) |
WebHttpRelayBinding | this binding maps to the WSHttpBinding
binding to enable a service to work with service bus features from.NET
Services (the relay counterpart establishes a listener in the cloud
instead of listening locally) |
WebHttpBinding | uses
the HTTP transport channel with “Web Message Encoding” which enables
data formats, such as Text and XML or JSON over HTTP in support of REST
service development (as explained in the upcoming REST Service Classes and Attributes section) |
System-provided bindings are optimized for specific scenarios. For example, the WSHttpBinding is designed for interoperability with services that implement various WS-* specifications. The BasicHttpBinding works well with ASMX 2.0 Web services.
Bindings can be further classified as interoperable bindings and WCF-to-WCF bindings,
whereas the former are suitable for cross-platform data exchange and
the latter are intentionally proprietary and require both the service
and its consumers to be implemented with .NET using WCF. The primary
motivation to use WCF-to-WCF bindings is increased runtime performance
optimization.
Interoperable bindings include BasicHttpBinding, WsHttpBinding, and WsDualHttpBinding. WCF-to-WCF bindings include NetTcpBinding, NetNamedPipeBinding, NetMsmqBinding, and NetPeerTcpBinding.
Most of the bindings are conceptually similar and leverage previous distributed technologies.
Here are some examples:
There are two bindings based on HTTP protocol, one with WS-* extensions and the other without. The BasicHttpBinding binding (which does not include WS-* extensions) is analogous to ASMX, whereas the WSHttpBinding binding (which does include WS-* extensions) is analogous to ASMX with WSE.
The NetTcpBinding binding is analogous to .NET Remoting.
WCF includes two MSMQ bindings, MsmqIntegrationBinding and NetMsmqBinding. The NetMsmqBinding does not support SOAP and is analogous to native MSMQ. The MsmqIntegrationBinding binding extends NetMsmqBinding to include SOAP support.
The NetNamedPipeBinding is analogous to named pipes and is suitable for communication between WCF processes on the same machine.
Besides
bindings that map to existing distributed technologies, there are a
couple of bindings that extend beyond more specialized distributed
platforms. For example, the wsFederationHttpBinding binding is designed to leverage the Identity Metasystem which is a part of Windows Cardspace.
Contract
Within the service
endpoint, the contract is a reference to the service type that is
exposed to the outside world. The contract is essentially used to
answer the question: “What capabilities does the service provide?” By
design, the service endpoint should be decoupled from the service
implementation, and the contact parameter links an endpoint to the
service implementation.
A contract is represented by the ContractDescription class in WCF, and contains a reference to an interface that defines the actual contract details (Figure 5).
A ContractDescription
object is used to describe contracts and their operations. Each
operation is based on a message exchange pattern. The name and
namespace attributes are used to uniquely identify the contract in the
service’s metadata.
REST Service Classes and Attributes
WCF supports popular REST content type formats, such as JSON, XML, ATOM, and RSS. .NET 3.5 introduced the System.ServiceModel.Web
assembly, which provides several classes and attributes that support
the development of REST services. As with regular Web services in WCF,
attributes are used to communicate intent to the System.ServiceModel runtime. Specifically, the following classes and attributes are available:
WebGet
WebInvoke
URITemplate
WebServiceHost
WebServiceHostFactory
REST attributes build upon and provide information to the aforementioned dispatcher mechanism (Figure 6) to enable the routing of messages to the appropriate internal service logic.
The WebGet Attribute
As part of the System.ServiceModel.Web assembly, the WebGet attribute is used to implement a service endpoint that is accessed by a consumer using the HTTP GET method.
The best way to understand this attribute is to revisit the WCF service contract. Here is a basic example:
Example 15.
using System; using System.ServiceModel; namespace HelloWorld { [ServiceContract] public interface IGreetings { [OperationContract] string Greet(string Name); } }
|
The ServiceContract attribute establishes the service contract and the OperationContract
attribute identifies which methods of the interface are actual
operations of the interface contract. After the service contract is
defined, it can be implemented as a .NET class, as shown here:
class Greetings : IGreetings
{
public string Greet(string Name)
{
return "Hello World";
}
}
...and with the WebGet attribute, the service operation can be converted as follows:
Example 16.
using System; using System.ServiceModel; using System.ServiceModel.Web; namespace HelloWorld { [ServiceContract] public interface IGreetings { [OperationContract] [WebGet( BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, UriTemplate = "/GreetingService/{Name}")] string Greet(string Name); } }
|
The WebGet attribute basically notifies the WCF runtime that the operation must be mapped to the HTTP Get method.
The WebGet attribute accepts the parameters listed in Table 2.
Table 2. Parameters for the WebGet attribute.
Parameter | Values | Description |
---|
BodyStyle | Bare
Wrapped
WrappedRequest
WrappedResponse | indicates to the runtime whether the request and response messages should be wrapped by the WCF infrastructure (when set to Bare no wrapping is provided) |
RequestFormat | Json
Xml | specifies the de-serialization format for all incoming HTTP requests |
ResponseFormat | Json
Xml | specifies
the serialization format for all outgoing HTTP responses (the request
and response objects can be formatted differently) |
UriTemplate | parameterized
relative URI | sets the relative REST-based URI for the operation and maps parameters from the URI to the operation contract |
The WebInvoke Attribute
Whereas the WebGet attribute is specifically used to map a service operation to the HTTP GET method, the WebInvoke
attribute allows service operations to be mapped to other HTTP methods.
Although it defaults to the POST method, it can be changed to PUT and
DELETE using the method parameter.
For example, using the WebInvoke attribute, the service operation in this example can be converted, as follows:
Example 17.
using System; using System.ServiceModel; using System.ServiceModel.Web; namespace HelloWorld { [ServiceContract] public interface IGreetings { [OperationContract] [WebInvoke( Method = "POST", UriTemplate ="Greet?Name={Name}")] string Greet(string Name); } }
|
The WebInvoke attribute includes all the same parameters as the WebGet attribute, including BodyStyle, RequestFormat, ResponseFormat, and UriTemplateMethod parameter. Method is used to specify the HTTP method that corresponds to the mapped operation. (explained shortly), but also contains the additional
In the next example, we specified POST as the HTTP method. A RESTful service can be consumed directly using the System.Net.WebClient class and the service consumer does not require a proxy object:
Example 18.
System.Net.WebClient client = new System.Net.WebClient(); client.UploadString ("http://localhost:8000/GreetingsService/ Greet?Name=John", "POST", String.Empty);
|
WCF UriTemplate Attribute
Finally, the UriTemplate attribute is used to map URI parameters to operation parameters. The URITemplate class is a part of the System.ServiceModel.Web
assembly and it uses placeholders to indicate parameters to be passed
to the method. The value of the property tells the runtime how to map
incoming requests and query string values to function arguments.
The following set of examples show a UriTemplate usage in different scenarios, each of which resolves to a WCF operation:
Example 19.
[WebGet(UriTemplate="/catalog/{category}")] public List<CatalogCategory> GetSubcategories(string category){}
|
If a request comes in as GET/catalog/drillBits, the WCF runtime will call:
Example 20.
GetSubcategories("drillBits")
|
Likewise, one could support a query string for the previous, as follows:
Example 21.
[WebGet(UriTemplate="/catalog?cat={category}")]
public List<CatalogCategory> GetSubcategories(string category){}
|
When parameters appear as part
of a query string, the infrastructure matches the parameters based on
their pairings instead of the location in the query. However, path
matches are always position-based.
That is, given the following template:
Example 22.
[WebGet(UriTemplate="/catalog?cat= {category}&sub={subcategory}")] public List<CatalogItem> GetItems(string category, string subcategory){}
|
...both of these URLs will have the same behavior:
GET /catalog?cat=drillBits&sub=carbide
GET /catalog?sub=carbide&cat=drillBits
These statements invoke:
Example 23.
GetItems("drillBits", "carbide");
|
...but as a path, we get different behavior:
Example 24.
[WebGet(UriTemplate= "/catalog/{category}/{subcategory}")] public List<CatalogItem> GetItems(string category, string subcategory){}
|
Both these URLs will have different behavior:
GET /catalog/drillBits/carbide
GET /catalog/carbide/drillBits
These statements invoke:
Example 25.
GetItems("drillBits", "carbide"); //GET /catalog/drillBits/carbide GetItems("carbide", "drillBits"); //GET /catalog/carbide/drillBits
|
Finally, the following code fragment demonstrates the use of the UriTemplate class:
Example 26.
UriTemplate template = new UriTemplate("{culture}/library/ {typeInformation}"); Uri baseAddress = new Uri("http://www.example.org/"); Uri formattedUri = template.BindByPosition( baseAddress, "en-US", "Article1.asp");
|
The output of this code is:
http://www.example.org/en-US/Article1.asp